package com.yunos.camera;

import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.Face;
import android.hardware.Camera.FaceDetectionListener;
import android.hardware.Camera.Parameters;
import android.os.AsyncTask;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.ScaleAnimation;

import com.way.camera.R;
import com.yunos.camera.CameraPreference.OnPreferenceChangedListener;
import com.yunos.camera.FocusOverlayManager.FocusUI;
import com.yunos.camera.PreviewGestures.SingleTapListener;
import com.yunos.camera.ui.CameraControls;
import com.yunos.camera.ui.ModuleIndicatorPanel.AnimatioinCallback;
import com.yunos.camera.ui.QRDetectResult;
import com.yunos.camera.ui.RenderOverlay;
import com.yunos.camera.ui.RotateImageButton;
import com.yunos.camera.ui.RotateImageView;
import com.yunos.camera.ui.ScanCard;
import com.yunos.camera.ui.ZoomRenderer;

public class ScanUI implements LocationManager.Listener,
FaceDetectionListener, FocusUI, SingleTapListener, AnimatioinCallback {

    private CameraActivity mActivity;
    private ComboPreferences mPreferencs;
    private ScanController mController;
    // private FaceView mFaceView;
    private RenderOverlay mRenderOverlay;
    //private FocusRenderer mFocusRenderer;
    private ZoomRenderer mZoomRenderer;
    private View mRootView;
    private PreviewGestures mGestures;
    //private volatile SurfaceHolder mSurfaceHolder;
    private CameraControls mCameraControls;
    private ShutterButton mShutterButton;
    private View mPreviewThumb;
    private View mScanLine;
    private RotateImageView mFlashButton;
    private Thumbnail mThumbnail;
    private int mFlashMode;
    private OnPreferenceChangedListener mListener;
    private ViewStub mScanCardViewStub;
    private ScanCard mScanCard;

    private ScaleAnimation mAnimation = null;
    private QRDetectResult pointView = null;
    private boolean mIsScanCameraIntent = false;
    private View mReviewCancelButton;
    private int mZoomMax;
    private List<Integer> mZoomRatios;
    private ZoomChangeListener mZoomChangeListener = new ZoomChangeListener();
    private Object mSurfaceTexture;
    private Parameters mParameters;

    public void setListener(OnPreferenceChangedListener listener) {
        mListener = listener;
    }

    public void setCodeType(int type) {
        mScanCard.setCodeType(type);
    }

    public ScanUI(CameraActivity activity, ScanController controller, View parent, ComboPreferences pref) {
        mActivity = activity;
        mController = controller;
        mRootView = parent;
        mPreferencs = pref;
        // Parse Intent
        mIsScanCameraIntent = Util.isScanIntent(mActivity.getIntent());
        initViews();
        initializeControlByIntent();
    }

    private void initViews() {
        // Controls from scan_module.xml
        mActivity.getLayoutInflater().inflate(R.layout.scan_module, (ViewGroup) mRootView, true);
        mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
        mScanCardViewStub = (ViewStub) mRootView.findViewById(R.id.scancard_view_stub);
        // Scan line for Animation
        mScanLine = mRootView.findViewById(R.id.scan_line);
        // Controls from camera_controls.xml
        mCameraControls = (CameraControls) mActivity.findViewById(R.id.camera_controls);
        mCameraControls.initViews(CameraActivity.SCANNER_MODULE_INDEX, mPreferencs);
        mShutterButton = (ShutterButton) mCameraControls.getPhotoShutter();
        mFlashButton = (RotateImageView) mCameraControls.getVideoFlash();
        pointView = (QRDetectResult) mRootView.findViewById(R.id.detect_result);
        //        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) pointView.getLayoutParams();
        //        lp.width = 108 * 8;
        //        lp.height = lp.width;
        //        pointView.requestLayout();
    }

    public void setPoints(int points[]) {
        //pointView.setPoints(points);
    }

    public View getRootView() {
        return mRootView;
    }

    // called from onResume but only the first time
    public void initializeFirstTime() {
        // Initialize shutter button.
        mShutterButton.setOnShutterButtonListener(mController);
        // mRootView.addOnLayoutChangeListener(mLayoutListener);
    }

    // called from onResume every other time
    public void initializeSecondTime(Camera.Parameters params) {
        initializeZoom(params);
    }

    private void initializeControlByIntent() {
        mCameraControls.initilizeControlByIntent(CameraActivity.SCANNER_MODULE_INDEX,
                mActivity.getIntent(), mPreferencs);
        if (mIsScanCameraIntent) {
            mActivity.getLayoutInflater().inflate(R.layout.review_module, mCameraControls);
            mReviewCancelButton = mCameraControls.findViewById(R.id.btn_cancel);
            mReviewCancelButton.setVisibility(View.GONE);
            mReviewCancelButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    mActivity.setResult(Activity.RESULT_CANCELED, new Intent());
                    mActivity.finish();
                }
            });
        }
    }

    // shutter button handling
    public boolean isShutterPressed() {
        return mShutterButton.isPressed();
    }

    @Override
    public void onFaceDetection(Face[] faces, Camera arg1) {
    }

    @Override
    public void showGpsOnScreenIndicator(boolean hasSignal) {
    }

    @Override
    public void hideGpsOnScreenIndicator() {
    }

    public void enablePreviewThumb(boolean enabled) {
        if (enabled) {
            mGestures.addTouchReceiver(mPreviewThumb);
            mPreviewThumb.setVisibility(View.VISIBLE);
        } else {
            mGestures.removeTouchReceiver(mPreviewThumb);
            mPreviewThumb.setVisibility(View.GONE);
        }
    }

    public void clearFaces() {
        // if (mFaceView != null) mFaceView.clear();
    }

    public void onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs,
            Camera.Parameters params, OnPreferenceChangedListener listener) {
        //        if (mFocusRenderer == null) {
        //            mFocusRenderer = new FocusRenderer(mActivity);
        //            mRenderOverlay.addRenderer(mFocusRenderer);
        //        }
        mParameters = params;
        if (mZoomRenderer == null) {
            mZoomRenderer = new ZoomRenderer(mActivity);
            //mRenderOverlay.addRenderer(mZoomRenderer);
        }
        // may be returned from other activity
        if (mScanCard != null && mScanCard.getVisibility() != View.VISIBLE) {
            mCameraControls.setBackgroundResource(R.drawable.camera_scan_mask);
        }
        if (mGestures == null) {
            // this will handle gesture disambiguation and dispatching
            mGestures = new PreviewGestures(mActivity, this, mZoomRenderer,
                    mActivity);
        }
        mGestures.reset();
        mGestures.setRenderOverlay(mRenderOverlay);

        // Add Unclickable Area to block focus action
        mGestures.addUnclickableArea(mActivity.findViewById(R.id.lower_controls));
        mGestures.addUnclickableArea(mActivity.findViewById(R.id.upper_block_area));

        if (mReviewCancelButton != null) {
            mGestures.addTouchReceiver(mReviewCancelButton);
        }
        mPreviewThumb = mActivity.findViewById(R.id.preview);
        mRenderOverlay.requestLayout();
        enablePreviewThumb(false);

        mGestures.addTouchReceiver(mFlashButton);

        if (mScanCard != null) {
            mGestures.addTouchReceiver(mScanCard);
        }

        mFlashButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mListener.onCameraFlashModeClicked(mFlashMode);
            }
        });

        initializeZoom(params);

        updateThumbnail();
        mAnimation = new ScaleAnimation(1, 1, 0, 1);
        mAnimation.setInterpolator(new DecelerateInterpolator());
        mAnimation.setRepeatCount(-1);
        mAnimation.setDuration(1500);
    }

    public boolean dispatchTouchEvent(MotionEvent m) {
        if (mGestures != null && mRenderOverlay != null) {
            return mGestures.dispatchTouch(m);
        }
        return false;
    }

    @Override
    public void onSingleTapUp(View v, int x, int y) {
        mController.onSingleTapUp(v, x, y);
    }

    public void enableGestures(boolean enable) {
        if (mGestures != null) {
            mGestures.setEnabled(enable);
        }
    }

    public boolean collapseCameraControls() {
        // Remove all the popups/dialog boxes
        boolean ret = false;
        return ret;
    }

    public void enableShutter(boolean enabled) {
        if (mShutterButton != null) {
            mShutterButton.setEnabled(enabled);
            Log.d("dyb", "shutter button enabled");
        }
    }

    public void pressShutterButton() {
        if (mShutterButton.isInTouchMode()) {
            mShutterButton.requestFocusFromTouch();
        } else {
            mShutterButton.requestFocus();
        }
        mShutterButton.setPressed(true);
    }

    public void initializeZoom(Parameters param) {
        if (param == null || !param.isZoomSupported())
            return;
        mZoomMax = param.getMaxZoom();
        mZoomRatios = param.getZoomRatios();
        // Currently we use immediate zoom for fast zooming to get better UX and
        // there is no plan to take advantage of the smooth zoom.
        if (mZoomRenderer == null) {
            mZoomRenderer = new ZoomRenderer(mActivity);
            mRenderOverlay.addRenderer(mZoomRenderer);
        }
        mZoomRenderer.setZoomMax(mZoomMax);
        mZoomRenderer.setZoom(param.getZoom(), false);
        mZoomRenderer.setZoomValue(mZoomRatios.get(param.getZoom()));
        mZoomRenderer.setOnZoomChangeListener(mZoomChangeListener);
    }
    
    public void zoomIn(Parameters param) {
        int currentZoom = param.getZoom();
        if (currentZoom < mZoomMax) {
            mZoomChangeListener.onZoomValueChanged(++currentZoom);
        }
    }

    public void zoomOut(Parameters param) {
        int currentZoom = param.getZoom();
        if (currentZoom > 0) {
            mZoomChangeListener.onZoomValueChanged(--currentZoom);
        }
    }
    
    private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
        @Override
        public void onZoomValueChanged(int index) {
            int newZoom = mController.onZoomChanged(index);
            if (mZoomRenderer != null) {
                mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom));
            }
        }

        @Override
        public void onZoomStart() {
        }

        @Override
        public void onZoomEnd() {
        }
    }

    public void initializeFlash(Parameters flash) {
        boolean hasFlash = false;
        List<String> supportedFlashMode = flash.getSupportedFlashModes();
        if (null != supportedFlashMode) {
            for (String s : supportedFlashMode) {
                    if (s.equals(Parameters.FLASH_MODE_TORCH)) {
                        hasFlash = true;
                        break;
                    }
            }
        }
        if (!hasFlash) {
            mFlashButton.setVisibility(View.GONE);
        } else {
            // mFlashButton.setVisibility(View.VISIBLE);
            String currentFlashMode = flash.getFlashMode();
            if (currentFlashMode.equals(Parameters.FLASH_MODE_TORCH)) {
                if (mIsScanCameraIntent) {
                    mFlashButton.setImageResource(R.drawable.ic_camera_light_on);
                }
                mFlashMode = ScanController.FLASH_MODE_TORCH;
            } else {
                if (mIsScanCameraIntent) {
                    mFlashButton.setImageResource(R.drawable.ic_camera_light_off);
                }
                mFlashMode = ScanController.FLASH_MODE_OFF;
            }
        }
    }

    public void onOrientationChanged(int orientation) {
        mCameraControls.onOrientationChanged(orientation);
        ((RotateImageButton) mCameraControls.getPhotoSetting()).setOrientation(orientation, true);
        ((RotateImageButton) mCameraControls.getEffectsButton()).setOrientation(orientation, true);
    }

    class UpdateThumbnailTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            mThumbnail = mActivity.getPhotoThumbnail();
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
        }
    }

    public void updateThumbnail() {
        UpdateThumbnailTask mTask = new UpdateThumbnailTask();
        mTask.execute();
    }

    public void showTextCopied() {
        mScanCard.setTextCopied();
    }

    public void showContactAdded() {
        mScanCard.setVCarddded();
    }

    public void animateToModule(int moduleIndex) {
        mCameraControls.setBackgroundColor(Color.TRANSPARENT);
        mCameraControls.animateToModule(moduleIndex, mPreferencs, mParameters, this);
    }

    @Override
    public void onAnimationEnd() {
        mController.onAnimationEnd();
    }

    public Object getSurfaceTexture() {
        return mSurfaceTexture;
    }

    public void setSurfaceTexture(Object st) {
        mSurfaceTexture = st;
    }

    public void updateFlashButton(String flashmode) {
        if (Parameters.FLASH_MODE_OFF.equals(flashmode)) {
            mFlashMode = ScanController.FLASH_MODE_OFF;
        } else if (Parameters.FLASH_MODE_TORCH.equals(flashmode)){
            mFlashMode = ScanController.FLASH_MODE_TORCH;
        }
        mCameraControls.updateVideoFlashButton(flashmode);
    }

    @Override
    public boolean hasFaces() {
        // inherited from FocusUI, we don't need it in ScanUI
        return false;
    }

    @Override
    public void clearFocus() {
        // inherited from FocusUI, we don't need it in ScanUI
    }

    @Override
    public void setFocusPosition(int x, int y) {
        // inherited from FocusUI, we don't need it in ScanUI
    }

    @Override
    public void onFocusStarted(boolean manual) {
        // inherited from FocusUI, we don't need it in ScanUI
    }

    @Override
    public void onFocusSucceeded(boolean timeOut) {
        // inherited from FocusUI, we don't need it in ScanUI
    }

    @Override
    public void onFocusFailed(boolean timeOut) {
        // inherited from FocusUI, we don't need it in ScanUI
    }

    @Override
    public void pauseFaceDetection() {
        // inherited from FocusUI, we don't need it in ScanUI
    }

    @Override
    public void resumeFaceDetection() {
        // inherited from FocusUI, we don't need it in ScanUI
    }

    public void stopAnimation() {
        if (mAnimation != null) {
            mAnimation.cancel();
        }
    }

    public void showScanUI(boolean flashSupport) {
        mCameraControls.setBackgroundResource(R.drawable.camera_scan_mask);
        mCameraControls.showIndicatorPanel();
        mScanLine.setVisibility(View.VISIBLE);
        if (flashSupport) {
            Util.fadeIn(mFlashButton);
        }
        showReviewUI();
        if (mScanCard != null) {
            mScanCard.setVisibility(View.GONE);
            mScanCard.resetScanCard();
        }
        mScanLine.setVisibility(View.VISIBLE);
        mScanLine.startAnimation(mAnimation);
    }

    public void hideScanUI() {
        mScanLine.setVisibility(View.INVISIBLE);
        mCameraControls.setBackgroundColor(Color.argb(128, 0, 0, 0));
        mCameraControls.hideIndicatorPanel();
        Util.fadeOut(mFlashButton);
        stopAnimation();
        hideReviewUI();
    }

    private void showReviewUI() {
        if (mIsScanCameraIntent) {
            Util.fadeIn(mReviewCancelButton);
        }
    }

    private void hideReviewUI() {
        if (mIsScanCameraIntent) {
            Util.fadeOut(mReviewCancelButton);
        }
    }

    public void initializeScanCard() {
        View parent = mScanCardViewStub.inflate();
        mScanCard = (ScanCard) parent.findViewById(R.id.scancard);
        mScanCard.setVisibility(View.INVISIBLE);
        mScanCard.setActionListener((ScanCard.ActionListener)mController);
        mGestures.addTouchReceiver(mScanCard);
    }

    public void updateOfflineCard(int type, String result) {
        mScanCard.updateOfflineCard(type, result);
        Util.fadeIn(mScanCard);
    }

    public void updateOnlineCard(String result, String postData) {
        mScanCard.updateOnlineCard(result, postData);
    }

    public boolean isScanCardShowing() {
        return mScanCard != null && mScanCard.getVisibility() == View.VISIBLE;
    }
}
